#include "stdafx.h"
#include "ParticleRenderer.h"
#include "RenderSystem.h"
#include "Camera.h"

ParticleRenderer::ParticleRenderer(void){
	m_frame = new OncePerFrame;
	m_object = new OncePerObject;
}


ParticleRenderer::~ParticleRenderer(void){
	delete m_frame;
	delete m_object;
}

bool ParticleRenderer::Init(int pre_alloc_size){
	//m_scene.reserve(pre_alloc_size);
	//m_visible_scene.reserve(pre_alloc_size);
	//m_sorted_scene.reserve(pre_alloc_size);

	return true;
}

void ParticleRenderer::Shut(){}

void ParticleRenderer::Render(RenderSystem* render_system, Camera* camera){
	CullScene(camera);
	RenderScene(render_system);
}

SceneObject* ParticleRenderer::Create(Shader* shader, Texture* texture, Renderable* renderable){
	SceneObject* object = new SceneObject;
	object->m_renderable = renderable;
	object->m_material.m_shader = shader;
	object->m_material.m_texture = texture;
	object->m_bounding_sphere.m_radius = renderable->m_vertex_buffer.m_radius;

	m_scene.push_back(object);
	return object;
}

void ParticleRenderer::Destroy(SceneObject* object){
	std::vector<SceneObject*>::iterator it=m_scene.begin();
	while(it!=m_scene.end()) {
		if((*it)==object) {
			delete object;
			m_scene.erase(it);
			break;
		};
		++it;
	};
}

void ParticleRenderer::CullScene(Camera* camera)
{
	using namespace DirectX;

	m_frame->projection = camera->GetProj();
	m_frame->view = camera->GetView();

	//DirectX::BoundingFrustum::CreateFromMatrix(m_frustum.m_frustum,m_frame->projection);
	//m_frustum.m_frustum.Transform(m_frustum.m_frustum,
	//	DirectX::XMMatrixInverse(nullptr, m_frame->view));

	//  cull all objects against the frustum
	m_visible_scene.clear();
	for (unsigned int i = 0; i < m_scene.size(); i++)
	{
		DirectX::BoundingSphere sphere(m_scene[i]->m_bounding_sphere.m_position, m_scene[i]->m_bounding_sphere.m_radius);

		//if (m_frustum.m_frustum.Intersects(sphere))
			m_visible_scene.push_back(m_scene[i]->m_id);
	}
}

void ParticleRenderer::RenderScene(RenderSystem* render_system)
{
	if (m_visible_scene.empty())
		return;

	unsigned int sh_id = 0;
	for (unsigned int i = 0; i < m_scene.size(); i++)
	{
		SceneObject* object = m_scene[i];

		if (sh_id != object->m_material.m_shader->m_id)
		{
			object->m_material.m_shader->SetVSConstant(0, sizeof(OncePerFrame), m_frame);
			sh_id = object->m_material.m_shader->m_id;
		}

		m_object->world = object->m_transform;
		object->m_material.m_shader->SetVSConstant(1, sizeof(OncePerObject), m_object);

		
		render_system->SelectShader(object->m_material.m_shader);
		render_system->SelectTexture(object->m_material.m_texture,0);
		render_system->SelectBlendState(object->m_material.m_states.m_blend);
		render_system->SelectDepthState(object->m_material.m_states.m_depth);
		render_system->SelectRasterizerState(object->m_material.m_states.m_rasterizer);
		render_system->SelectIndexBuffer(&object->m_renderable->m_index_buffer);
		render_system->SelectVertexBuffer(&object->m_renderable->m_vertex_buffer,0);
		render_system->Apply();

		if (object->m_renderable->m_index_buffer.m_buffer)
			render_system->DrawIndexed(PRIM_TRIANGLE_LIST, 0, 0, object->m_renderable->m_count);
		else
			render_system->Draw(PRIM_TRIANGLE_LIST, 0, object->m_renderable->m_count);

	}
}